﻿using HandyControl.Interactivity;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace MyTools.Helpers
{
    /// <summary>
    /// 唯一进程
    /// </summary>
    public static class ProcessOnlyHelper
    {
        #region Win32 API
        private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
        [DllImport("user32.dll")]
        private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
        [DllImport("user32.dll")]
        private static extern IntPtr GetParent(IntPtr hWnd);
        [DllImport("user32.dll")]
        private static extern bool IsWindowVisible(IntPtr hWnd);
        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int processId);
        ///<summary>
        /// 该函数设置由不同线程产生的窗口的显示状态
        /// </summary>
        /// <param name="hWnd">窗口句柄</param>
        /// <param name="cmdShow">指定窗口如何显示。查看允许值列表，请查阅ShowWindow函数的说明部分</param>
        /// <returns>如果函数原来可见，返回值为非零；如果函数原来被隐藏，返回值为零</returns>
        [DllImport("User32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
        /// <summary>
        ///  该函数将创建指定窗口的线程设置到前台，并且激活该窗口。键盘输入转向该窗口，并为用户改各种可视的记号。
        ///  系统给创建前台窗口的线程分配的权限稍高于其他线程。 
        /// </summary>
        /// <param name="hWnd">将被激活并被调入前台的窗口句柄</param>
        /// <returns>如果窗口设入了前台，返回值为非零；如果窗口未被设入前台，返回值为零</returns>
        [DllImport("User32.dll", EntryPoint = "SetForegroundWindow")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
        /// <summary>
        /// 激活指定窗口
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="fAltTab">是否使最小化的窗口还原</param>
        [DllImport("user32.dll")]
        private static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
        /// <summary>
        /// 根据窗口标题查找窗体
        /// </summary>
        /// <param name="lpClassName"></param>
        /// <param name="lpWindowName"></param>
        /// <returns></returns>
        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll")]
        private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
        #endregion
        //通过创建一个全局的Mutex对象来确保同一时间内只有一个程序实例在运行。
        private static Mutex mutex = new();
        /// <summary>
        /// 注册应用为单例模式
        /// </summary>
        /// <param name="appUniqueName">应用唯一名称(推荐使用GUID)</param>
        public static bool RegisterSingleInstance(string appUniqueName)
        {
            mutex = new Mutex(true, appUniqueName, out var createdNew);
            return createdNew;
        }
        /// <summary>
        /// 检查是否已启动，启动则顶置
        /// </summary>
        /// <param name="mutexName">进程唯一编号</param>
        /// <param name="isShow">如果存在：是否显示窗口</param>
        /// <returns></returns>
        public static bool Check(string mutexName, string windowTitle, bool isShow = true)
        {
            bool createdNew = RegisterSingleInstance("MyToolsUniqueName");
            if (createdNew)
            {
                return false;
            }

            // 顶置已运行程序窗口
            if (isShow)
            {
                var current = Process.GetCurrentProcess();
                var processes = Process.GetProcessesByName(current.ProcessName);
                if (processes?.Length == 0)
                {
                    return false;
                }

                var process = processes?.FirstOrDefault(o => o.Id != current.Id)!;
                var mwh = process.MainWindowHandle;
                if (process.MainWindowHandle == IntPtr.Zero)
                {
                    mwh = FindWindow(null, "MyTools");
                    ShowWindow(mwh, 5);
                    SendMessage(mwh, 0x0018, IntPtr.Zero, new IntPtr(3));
                }
                SwitchToThisWindow(mwh, true);
            }
            return true;
        }
    }
}
